package com.liu.gateway.gateway.filter;


import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.liu.common.commons.AuthLoginClientConfig;
import com.liu.common.enums.HttpStatus;
import com.liu.gateway.gateway.service.AuthService;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author lxh
 * 请求合法性过滤器
 * @date 2018/2/9
 */
@Component
@Slf4j
public class RequestZuulFilter extends ZuulFilter {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private AuthService authService;

/**
过虑器的类型
pre：请求在被路由之前执行

routing：在路由请求时调用

post：在routing和errror过滤器之后调用

error：处理请求时发生错误调用

*/
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

/**
* 过虑器序号，越小越被优先执行
*/
    @Override
    public int filterOrder() {
        return -1;
    }

    /**
     * 返回true表示要执行此过虑器
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        //网关处理要直接返回的请求就不再往下转发 直接返回
        if(!ctx.sendZuulResponse()){
            return false;
        }
        //放行swagger资源访问,不受该过滤器过滤
        if ( ctx.getRequest().getServletPath().endsWith("/v2/api-docs")){
            return false;
        }
        //拦截所有的请求
        return  true;
//                ctx.getRequest().getRequestURI().contains("/oauth/token");
    }

/**
*过虑器的内容
 * 登录请求：/auth/oauth/token
         * 1.  登录端： webapp    图形验证码登录，判断图形验证码是否有效
         * 2.  登录端： mobile    验证手机验证码是否有效
 * 除过登录以外的请求
 *      校验请求头是否携带token，以及token是否有效
 *
* @return
*/
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest req = ctx.getRequest();
        //设置response对象参数
        HttpServletResponse response = ctx.getResponse();
        response.setContentType("application/json;charset=UTF-8");
        response.setHeader("Access-Control-Allow-Origin","*");
        String path = req.getServletPath();
        String auth = req.getHeader("Authorization");
        HttpStatus httpStatus = null;
        HashMap<String, Object> responMap = Maps.newHashMap();
        if (StringUtils.equals(path,"/auth/oauth/token")){
            //用户登录
            // 验证码校验 处理图片验证码验证,移动端手机号校验 处理短信验证码
            httpStatus = checkCaptcha(req, auth);
        }else {
            //其他请求   非法请求拦截校验
             httpStatus = checkBadRequest(req);
        }
        if (null != httpStatus) {
            ctx.getResponse().setStatus(httpStatus.value());
            responMap.put("code", httpStatus.value());
            responMap.put("msg", httpStatus.msg());
            responMap.put("timestamp", System.currentTimeMillis());
            ctx.setResponseBody(JSON.toJSONString(responMap));
            // zuul 网关直接返回响应，不让请求访问后续的接口 ，需要在 shouldFilter进行判断
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            log.error(LocalDateTime.now().toString() + " :网关拦截网络层状态码:" + ctx.getResponseStatusCode() +
                    "网关拦截路径:" + path + ":  内部异常信息：" + JSON.toJSONString(responMap));
        }
        return null;
    }

    /**
     * 校验请求头是否携带token，以及token是否有效
     * @param req
     * @return
     */
    private HttpStatus checkBadRequest(HttpServletRequest req) {
        //从header中取jwt
        String jwtFromHeader = authService.getJwtFromHeader(req);
        if(StringUtils.isEmpty(jwtFromHeader)){
            //拒绝访问,非法访问，无jwt令牌
           return HttpStatus.FORBIDDEN;
        }
//        从redis取出jwt的过期时间
//        long expire = authService.getExpire(jwtFromHeader);
//        if(expire<0){
//            return HttpStatus.UNAUTHORIZED;
//        }
        return null;
    }

    private HttpStatus checkCaptcha(HttpServletRequest req, String auth) {
        //采用base64解码获取的客户端信息
        if (StringUtils.isBlank(auth)){
            return HttpStatus.AUTHORIZED_ERROR;
        }
        //获取到 clientId:secret 格式
        String client = Splitter.on(" ").splitToList(auth).get(1);
        //base64解码
        byte[] decode = Base64Utils.decode(client.getBytes());
        String clientAuth = new String(decode);

        //管理系统图片验证码 登录
        if(StringUtils.startsWith(clientAuth, AuthLoginClientConfig.WEB_APP_CLIENT_ID)){
          String captcha = Objects.nonNull(req.getParameter("captcha")) ? String.valueOf(req.getParameter("captcha")) : null; //图形验证码
          String captchaKey =  Objects.nonNull(req.getParameter("captchakey")) ? String.valueOf(req.getParameter("captchakey")) : null; //图形验证码captchaKey
        if(StringUtils.isBlank(captcha)) {
            return HttpStatus.ZUUL_CAPTCHA_NULL;
        }
        String redisCaptcha = stringRedisTemplate.boundValueOps(captchaKey).get();
        if (StringUtils.isBlank(redisCaptcha)){
            return HttpStatus.ZUUL_CAPTCHA_INVALID;
        }
        if(!StringUtils.equalsIgnoreCase(captcha,redisCaptcha)) {
            return HttpStatus.ZUUL_CAPTCHA_ERROR;
        }
        }
        //app短信验证码，此处后期可能会改参数名
        if(StringUtils.equals(clientAuth, AuthLoginClientConfig.MOBILE_CLIENT_ID)){
            String mobile =  Objects.nonNull(req.getParameter("mobile")) ? String.valueOf(req.getParameter("mobile")) : null; //手机号
            String code = Objects.nonNull(req.getParameter("code")) ? String.valueOf(req.getParameter("code")) : null; //手机验证码
            if(StringUtils.isEmpty(code) ) {
                return HttpStatus.ZUUL_CAPTCHA_NULL;
            }
            String redisCaptcha = stringRedisTemplate.boundValueOps(mobile).get();
            if(null == redisCaptcha){
                return HttpStatus.ZUUL_CAPTCHA_INVALID;
            }
            if(!StringUtils.equals(code,redisCaptcha)) {
                return HttpStatus.ZUUL_CAPTCHA_ERROR;
            }
        }
                return null;
    }


    private Map<String,Object> getRequestBodyParams(HttpServletRequest request){
        Map<String,Object> params = new HashMap<>();
        BufferedReader br;
        try {
            br = request.getReader();
            String str, wholeStr = "";
            while((str = br.readLine()) != null){
                wholeStr += str;
            }
            if(StringUtils.isNotEmpty(wholeStr)){
                params = JSON.parseObject(wholeStr,Map.class);
            }
        } catch (IOException e1) {
            log.error("request请求body解析错误");
        }
        return params;
    }

}
